/*
 * Copyright (C) <2009>
 *
 * <Rishi B Agrawal> <Sneha Hendre>
 * <rishi.b.agrawal@gmail.com> <sneha.hendre@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "../include/ohsm.h"
#include "ohsm_u.h"

int
parseinfo_device(xmlDocPtr doc, xmlNodePtr cur, unsigned int *tiers,
		  unsigned int *devices)
{

  xmlChar *key;
  int no;
  unsigned int temp;
  int retval = 0;

  cur = cur->xmlChildrenNode;
  cur = cur->next;

  if ((!xmlStrcmp(cur->name, (const xmlChar *) "NR_TIERS"))) {

	key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	temp = validate_key(key);

	if (temp == -1) {
		no = (int) xmlGetLineNo(cur);
		printf("\nOHSM: [%d] : wrong value in <info><tiers> tag", no);
		printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
		xmlFree(key);
		return -1;
	} else
		*tiers = temp;

	if (*tiers > MAX_TIER_ALLOWED) {
		no = (int) xmlGetLineNo(cur);
		printf
		("\n[%d]:error Number of tiers entered more than ohsm supports",
		no);
		xmlFree(key);
		return -1;
	}
	xmlFree(key);
  }
  cur = cur->next->next;

  if ((!xmlStrcmp(cur->name, (const xmlChar *) "NR_DEVICES"))) {
	key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	temp = validate_key(key);

	if (temp == -1) {
		no = (int) xmlGetLineNo(cur);
		printf("\nOHSM: [%d] : wrong value in <info><devices> tag", no);
		printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
		xmlFree(key);
		return -1;
	} else
	  *devices = temp;
	xmlFree(key);
  }
  return retval;
}


int
parsetier(xmlDocPtr doc, xmlNodePtr cur, unsigned int devices)
{

  xmlChar *key;
  char *temp_name = NULL;
  int retval = 0, cnt_devices = 0, no;
  unsigned int temp, ctr = 0, target = 0, major, minor;
  struct stat buf;

  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (const xmlChar *) "DEVICE"))) {
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		cnt_devices++;

		if (cnt_devices > devices) {
			printf
			("\n No of devices less than specified");
			return -1;
		} else {

			temp_name = (char *) key;
			retval = stat(temp_name, &buf);

			if (retval) {
				no = (int) xmlGetLineNo(cur);
				printf("\n[%d]:error device %s is not present",
				no,	temp_name);
				return retval;
			}

			if (!S_ISBLK(buf.st_mode)) {
				no = (int) xmlGetLineNo(cur);
				printf
				("\n[%d]:error device %s is not valid device",
				no, temp_name);
				return -1;
			}

			major = MAJOR(buf.st_rdev);
			minor = MINOR(buf.st_rdev);

			for (ctr = 0; ctr < dev_info->dinfo_count; ++ctr) {
				if (dev_info->device[ctr].dev_num == MKDEV(major, minor)) {
					strcpy(dev_info->device[ctr].dev_name, temp_name);
					break;
				}
			}

			if (ctr >= dev_info->dinfo_count) {
				printf("\nInvialid device specified.");
				return -1;
			}
			target = ctr;
			xmlFree(key);
		}
	}
	cur = cur->next->next;

	if ((!xmlStrcmp(cur->name, (const xmlChar *) "TIER"))) {
		key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
		temp = validate_key(key);

		if (temp == -1) {
			no = (int) xmlGetLineNo(cur);
			printf("\n[%d] : wrong value in <info><tiers> tag", no);
			printf("\n[%d] : fatal : cannot proceed further", no);
			return -1;
		}

		dev_info->device[target].tier = temp;
		xmlFree(key);
	 }
	cur = cur->next->next;
  }

  if (cnt_devices < devices) {
	printf
	("\nOHSM: number of devices in <info><devices> greater than specified");
	return -1;
  }
  return 0;
}

int
parsedoc_t(char *docname)
{

  xmlDocPtr doc;
  xmlNodePtr cur;
  int retval = 0;
  unsigned int tiers, devices;

  doc = xmlParseFile(docname);
  if (!doc) {
	fprintf(stderr, "Document not parsed successfully. \n");
	xmlFreeDoc(doc);
	return -1;
  }

  cur = xmlDocGetRootElement(doc);
  if (!cur) {
	fprintf(stderr, "empty document\n");
	xmlFreeDoc(doc);
	return -1;
  }

  if (xmlStrcmp(cur->name, (const xmlChar *) "TIER_DEVICE_MAP")) {
	fprintf(stderr,
		"Invalid document Root element not equal to <DEV_TIER_MAP>\n");
	xmlFreeDoc(doc);
	return -1;
  }

  cur = cur->xmlChildrenNode;
  cur = cur->next;
  while (cur != NULL) {
	if ((!xmlStrcmp(cur->name, (xmlChar *) "INFO"))) {
		retval = parseinfo_device(doc, cur, &tiers, &devices);

		if (retval)
			return retval;
		dev_info->nr_tiers = tiers;
		dev_info->nr_devices = devices;
	}
	cur = cur->next->next;

	if ((!xmlStrcmp(cur->name, (const xmlChar *) "DEV_TIER"))) {
		retval = parsetier(doc, cur, devices);
		if (retval)
			return retval;
	}
	cur = cur->next->next;
  }
  xmlFreeDoc(doc);
  return 0;
}

int
ohsm_get_tier_device_info(char *filename)
{

  int retval = 0;
  char cmd1[80];

  sprintf(cmd1, "xmllint --valid --noout %s", filename);
  retval = system(cmd1);

  if (!retval)
	retval = parsedoc_t(filename);
  return retval;
}
